# -*- coding: utf-8 -*-
__author__ = 'hzchenxingxing'
from flask import Flask, jsonify
from flask.ext.restful import Api
from flask.ext.sqlalchemy import SQLAlchemy
import Queue
import memcache
import time
import thread
import flask_excel as excel
from sqlalchemy.orm import sessionmaker,scoped_session
from sqlalchemy import create_engine

memcache.Client = type('Client', (object,), dict(memcache.Client.__dict__))
# Client.__init__ references local, so need to replace that, too
class Local(object):
    pass
memcache.local = Local

adjust_poolsize_lock = thread.allocate_lock()

class PoolClient(object):
    '''Pool of memcache clients that has the same API as memcache.Client'''
    def __init__(self, min_pool_size, max_pool_size, pool_timeout,buffer_time, *args, **kwargs):
        self.pool_timeout = pool_timeout
        self.pool_size = min_pool_size
        self.queue = Queue.Queue()
        self.args = args
        self.kwargs = kwargs
        self.min_pool_size = min_pool_size
        self.max_pool_size = max_pool_size
        self.buffer_time = buffer_time
        for _i in range(self.pool_size):
            self.queue.put(memcache.Client(*args, **kwargs))

    def __getattr__(self, name):
        return lambda *args, **kw: self._call_client_method(name, *args, **kw)

    def _call_client_method(self, name, *args, **kwargs):
        try:
            client = self.queue.get(timeout=self.pool_timeout)
        except Queue.Empty:
            global adjust_poolsize_lock
            if adjust_poolsize_lock.locked():
                pass
            else:
                adjust_poolsize_lock.acquire()
                self._adjust_pool_size(1)
                adjust_poolsize_lock.release()
            return

        try:
            return getattr(client, name)(*args, **kwargs)
        finally:
            print name
            if 'test_xx' in args:
                time.sleep(10)
            self.queue.put(client)

    def _get_size(self):
        return self.queue.qsize()

    def _adjust_pool_size(self,adjust_factor):
        new_pool_size = int(self.pool_size * (1 + adjust_factor))
        if new_pool_size > self.max_pool_size:
            new_pool_size = self.max_pool_size
        elif new_pool_size < self.min_pool_size:
            new_pool_size = self.min_pool_size

        if new_pool_size > self.pool_size:
            for _i in range(int(new_pool_size-self.pool_size)):
                self.queue.put(memcache.Client(*(self.args),**(self.kwargs)))
        else:
            for _i in range(int(self.pool_size-new_pool_size)):
                item = self.queue.get(memcache.Client(*(self.args),**(self.kwargs)))
                del item
        self.pool_size = new_pool_size

    def dynamic_config_pool_size(self):
        if self._get_size() < self.get_pool_size()/3:
            
            self._adjust_pool_size(1)
        elif self._get_size() > self.get_pool_size()/3 *2:
            time.sleep(self.buffer_time)
            self._adjust_pool_size(-0.5)
        else:
            pass

    def get_pool_size(self):
        return self.pool_size

class APP(Flask):
    def __init__(self, dbconfig, openid, auth_enable):
        Flask.__init__(self,__name__)
        self.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://%s:%s@%s:%s/%s' %(dbconfig['fulllink']["user"],
                                                                            dbconfig['fulllink']["passwd"],
                                                                            dbconfig['fulllink']["host"], 
                                                                            dbconfig['fulllink']["port"],
                                                                            dbconfig['fulllink']['db'])
        self.config['SQLALCHEMY_BINDS'] = {
            'fulllink':  self.config['SQLALCHEMY_DATABASE_URI'],
            'cmdb': 'mysql://%s:%s@%s:%s/%s' % (dbconfig['cmdb']["user"],
                                                dbconfig['cmdb']["passwd"],
                                                dbconfig['cmdb']["host"], 
                                                dbconfig['cmdb']["port"],
                                                dbconfig['cmdb']['db'])
        }
        self.config['SECRET_KEY'] = openid['SECRET_KEY']
        self.config['LOGIN_DISABLED'] = not auth_enable
        self.config['SQLALCHEMY_POOL_SIZE'] = 80
        self.config['SQLALCHEMY_MAX_OVERFLOW'] = 80

        self.db = SQLAlchemy(self,session_options={'autocommit': True})
    def get_db(self):
        return self.db

    def get_scoped_session(self):
        return self.db.create_scoped_session()

    def get_api(self):
        return Api(self,catch_all_404s=True)

    def get_excel(self):
        return excel

    def get_memcache_conn(self,config):
        return PoolClient(config['min_pool_size'],config['max_pool_size'],config['pool_timeout'],config['buffer_time'],config['memcache_servers'])
